package custom.base.http.retrofit;

import android.content.Context;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import custom.base.data.Global;
import custom.base.http.AppApi;
import custom.base.http.BaseRequest;
import custom.base.http.TokenManager;
import custom.base.log.GlobeLog;
import custom.base.log.MLog;
import custom.base.utils.FileUtils;
import custom.base.utils.TxtUtil;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import me.jessyan.progressmanager.ProgressManager;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import okio.BufferedSource;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by luozi on 2015/12/30.
 * baseRequest include requestString and requestObject and requestList
 */
public class IRequest extends BaseRequest {

    private AppApi appApi;
    private Retrofit retrofit;
    private OkHttpClient okHttpClient;
    private Context mContext;

    public IRequest(Context context) {
        super(context);
        mContext = context;
        init();
    }

    private static IRequest instance = null;

    /**
     * 单例对象置空操作，用于重新生成单例对象时使用
     */
    public static void setInstanceNull() {
        instance = null;
    }

    public static IRequest getInstance(Context context) {
        synchronized (IRequest.class) {
            if (instance == null) {
                instance = new IRequest(context);
            }
        }
        return instance;
    }

    /**
     * 父类构造函数
     */
    private void init() {
        /**
         * 请求拦截器，修改请求header
         */
        Interceptor requestInterceptor = new Interceptor() {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Request oldRequest = chain.request();
                long timeStamp = System.currentTimeMillis() / 1000;

                // 添加新的参数
                HttpUrl.Builder authorizedUrlBuilder = null;
                // 新的请求
                Request newRequest = null;
                if (oldRequest.url().query() != null || !FileUtils.haveSuffix(oldRequest.url().url().getPath())) {//不是下载文件才附加参数
                    authorizedUrlBuilder = oldRequest.url()
                            .newBuilder()
                            .scheme(oldRequest.url().scheme())
                            .host(oldRequest.url().host());

                    String token = TokenManager.getInstance(context).getToken();
                    newRequest = oldRequest.newBuilder()
                            .method(oldRequest.method(), oldRequest.body())
                            .url(authorizedUrlBuilder.build())
                            .addHeader("Authorization", "Bearer " + token)
                            .addHeader("tenant-id", "1")
                            .build();

                    //本次使用的token
//                    MLog.d("OkHttp", "本次使用的token：" + token);

                    if ("POST".equals(newRequest.method())) {
                        if (newRequest.body() != null && oldRequest.body() instanceof FormBody) {
                            FormBody formBody = ((FormBody) newRequest.body());
                            for (int i = 0; i < formBody.size(); i++) {
                                MLog.d("OkHttp", "OkHttp post 携带参数->  " + formBody.name(i) + "=" + formBody.value(i));
                            }
                        }
                    }

                }


                return newRequest == null ? chain.proceed(oldRequest) : chain.proceed(newRequest);
            }
        };
        /**自定义日志拦截器*/
        Interceptor logInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                try {
                    Request request = chain.request();
                    RequestBody requestBody = request.body();
                    if (requestBody.contentLength() > 167771160) {//内容体大于10m就不写日志避免崩溃 这是文件请求
                        return chain.proceed(request);
                    }

                    String body = null;
                    if (requestBody != null) {
                        Buffer buffer = new Buffer();
                        requestBody.writeTo(buffer);

                        Charset charset = Charset.forName("UTF-8");
                        MediaType contentType = requestBody.contentType();
                        if (contentType != null) {
                            charset = contentType.charset(Charset.forName("UTF-8"));
                        }
                        body = buffer.readString(charset);
                    }

                    long startNs = System.nanoTime();
                    Response response = chain.proceed(request);
                    long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);

                    //返回实体类处理
                    ResponseBody responseBody = response.body();
                    String rBody = null;
                    if (responseBody.source() != null) {
                        BufferedSource source = responseBody.source();
                        source.request(Long.MAX_VALUE); // Buffer the entire body.
                        Buffer buffer = source.buffer();

                        Charset charset = Charset.forName("UTF-8");
                        MediaType contentType = responseBody.contentType();
                        if (contentType != null) {
                            try {
                                charset = contentType.charset(Charset.forName("UTF-8"));
                            } catch (UnsupportedCharsetException e) {
                                e.printStackTrace();
                            }
                        }
                        rBody = buffer.clone().readString(charset);
                    }
                    addLog(request, rBody, tookMs);
                    return response;
                } catch (Exception e) {
                    Request request = chain.request();
                    addLog(request, e.getMessage(), -1);
                    return chain.proceed(request);
                }
            }
        };
        X509TrustManager xtm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                X509Certificate[] x509Certificates = new X509Certificate[0];
                return x509Certificates;
            }
        };

        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");

            sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        //日志
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

//        OkHttpClient.Builder builder = ProgressHelper.addProgress(null)
        // 构建 OkHttpClient 时,将 OkHttpClient.Builder() 传入 with() 方法,进行初始化配置
        OkHttpClient.Builder builder = ProgressManager.getInstance().with(new OkHttpClient.Builder())
//        okHttpClient = builder
                .connectTimeout(TIME_OUT_S, TimeUnit.SECONDS)
                .readTimeout(TIME_OUT_S, TimeUnit.SECONDS)
                .writeTimeout(TIME_OUT_S, TimeUnit.SECONDS)
                .addInterceptor(requestInterceptor)
                .sslSocketFactory(sslContext.getSocketFactory(), xtm)
                .hostnameVerifier(DO_NOT_VERIFY);

        if (Global.getInstance().isDebugMode()) {//只有调试模式才打印请求日志
            builder.addInterceptor(logInterceptor);
            builder.addInterceptor(logging);
        }
        okHttpClient = builder.build();
        okHttpClient.connectionSpecs();

        if (retrofit == null) {
            Gson gson = new GsonBuilder()
                    .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                    .create();

            retrofit = new Retrofit.Builder()
                    .baseUrl(getAPPUrl())
                    .client(okHttpClient)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(gson))
//                    .addConverterFactory(ScalarsConverterFactory.create())
                    .build();
        }


        if (appApi == null)
            appApi = retrofit.create(AppApi.class);
    }

    /**
     * 得到api
     */
    public AppApi getAppApi() {
        if (appApi == null)
            init();
        return appApi;
    }

    private void addLog(Request request, String content, long time) {
        String url = request.url().toString();
        if (request.body() != null) {//如果实体类里有值的话则拼成网络请求地址
            if (request.body() instanceof FormBody) {
                FormBody formBody = ((FormBody) request.body());
                url += "?";
                for (int i = 0; i < formBody.size(); i++) {
                    if (!TxtUtil.isEmpty(formBody.value(i))) {
                        String name = formBody.name(i);
                        String value = formBody.value(i);

                        if (i != 0) {
                            url += "&";
                        }
                        url += name;
                        url += "=";
                        url += value;
                    }
                }
            }
        }
        int i1 = url.lastIndexOf("?");
        int i2 = url.lastIndexOf("/", i1 - 2);
        if (i1 == -1) {
            i1 = url.length() - 1;
        }
        if (i2 == -1) {
            i2 = url.length() - 2;
        }
        String interfaceName = url.substring(i2 + 1, i1);
        interfaceName = url.substring(url.lastIndexOf("/", i1 - interfaceName.length() - 2) + 1, i1);//取方法的两级
        GlobeLog.getIntance().addLog(mContext, "网络日志（" + interfaceName + "）", "请求方式：" + request.method() + "  请求耗时：" + time + "ms"
                + "\n请求地址："
                + url + "\n\n请求结果：\n" + content);

        Log.d("\n网络日志（" + interfaceName + "）", "请求方式：" + request.method() + "  请求耗时：" + time + "ms"
                + "\n请求地址："
                + url + "\n\n请求结果：\n" + content);

        Log.d("\n网络日志（" + interfaceName + "）", "---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");


    }

}
